package com.the_ring.chapter15.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.Scroller;

import androidx.annotation.Nullable;

import java.util.List;

public class CurveView extends View {



    public CurveView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        viewWidth = getMeasuredWidth();
        viewHeight = getMeasuredHeight();
    }

    /**
     * 计算出翻页的折边的位置点的坐标
     */
    private PointF a, f, g, e, h, c, j, b, k, d, i;    // 贝塞尔曲线的各个关联点
    // 计算各点坐标
    private void calcEachPoint(PointF a, PointF f) {
        g.x = (a.x + f.x) / 2;
        g.y = (a.y + f.y) / 2;
        e.x = g.x - (f.y - g.y) * (f.y - g.y) / (f.x - g.x);
        e.y = f.y;
        h.x = f.x;
        h.y = g.y - (f.x - g.x) * (f.x - g.x) / (f.y - g.y);
        c.x = e.x - (f.x - e.x) / 2;
        c.y = f.y;
        j.x = f.x;
        j.y = h.y - (f.y - h.y) / 2;
        b = getCrossPoint(a, e, c, j);
        k = getCrossPoint(a, h, c, j);
        d.x = (c.x + 2 * e.x + b.x) / 4;
        d.y = (2 * e.y + c.y + b.y) / 4;
        i.x = (j.x + 2 * h.x + k.x) / 4;
        i.y = (2 * h.y + j.y + k.y) / 4;
    }

    // 计算两条线的交点坐标
    private PointF getCrossPoint(PointF firstP1, PointF firstP2, PointF secondP1, PointF secondP2) {
        float dxFirst = firstP1.x - firstP2.x, dyFirst = firstP1.y - firstP2.y;
        float dxSecond = secondP1.x - secondP2.x, dySecond = secondP1.y - secondP2.y;
        float gapCross = dxSecond * dyFirst - dxFirst * dySecond;
        float firstCross = firstP1.x * firstP2.y - firstP2.x * firstP1.y;
        float secondCross = secondP1.x * secondP2.y - secondP2.x * secondP1.y;
        float pointX = (dxFirst * secondCross - dxSecond * firstCross) / gapCross;
        float pointY = (dyFirst * secondCross - dySecond * firstCross) / gapCross;
        return new PointF(pointY, pointY);
    }

    /**
     * 获得下一页的区域
     */
    private int viewWidth, viewHeight;      // 视图的宽度和高度
    private Bitmap nextBitmap;              // 下一页的位图

    // 绘制下一页
    private void drawNextView(Canvas canvas, Path currentPath) {
        canvas.save();  // 保存画布
        Path nextPath = getNextPath();  // 获得下一页的轮廓路径
        nextPath.op(currentPath, Path.Op.DIFFERENCE);   // 去除当前页的部分
        nextPath.op(getBackPath(), Path.Op.DIFFERENCE); // 去除背面页的部分
        canvas.clipPath(nextPath);  // 根据指定路径裁剪画布
        canvas.drawBitmap(nextBitmap, null, new RectF(0, 0, viewWidth, viewHeight), null);
        canvas.restore();   // 还原画布
    }

    // 获得下一页的轮廓路径
    private Path getNextPath() {
        Path nextPath = new Path();
        nextPath.lineTo(0, viewHeight);         // 从左下角开始
        nextPath.lineTo(viewWidth, viewHeight);     // 移动到右下角
        nextPath.lineTo(viewWidth, 0);          // 移动到右上角
        nextPath.close();                           // 闭合区域
        return nextPath;
    }

    // 获得背面页的轮廓路径
    private Path getBackPath() {
        Path backPath = new Path();
        backPath.moveTo(i.x, i.y);
        backPath.lineTo(d.x, d.y);
        backPath.lineTo(b.x, b.y);
        backPath.lineTo(a.x, a.y);
        backPath.lineTo(k.x, k.y);
        backPath.close();
        return backPath;
    }

    /**
     * 在手指触摸过程中，要实时计算个坐标点的位置，并调整书页的画面绘制
     */
    private static final int CLICK_TOP = 1;     // 点击了上面部分
    private static final int CLICK_BOTTOM = 2;  // 点击了下面部分
    private int mClickType = CLICK_BOTTOM;      // 点击类型
    private boolean needMove = false;           // 是否需要移动
    private boolean needChange = false;         // 是否需要改变图像

    private int mCurrentPos = 0;                // 当前页
    private List<String> mPathList;             // 资源路径

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        float x = event.getX();
        float y = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                needMove = !((x <=  viewWidth / 2 && mCurrentPos == 0)
                        || (x >= viewWidth / 2 && mCurrentPos == mPathList.size()));
                if (needMove) {
                    if (x <= viewWidth / 2) {
                        exchangeBitmap(false);  // 改变当前显示的图像
                    }
                    int clickType = (y <= viewHeight / 2) ? CLICK_TOP : CLICK_BOTTOM;
                    showTouchResult(x, y, clickType);       // 显示触摸结果
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (needMove) {
                    showTouchResult(x, y, mClickType);  // 显示触摸结果
                }
                break;
            case MotionEvent.ACTION_UP:
                if (needMove) {
                    needChange = x < viewWidth / 2;
                    if (needChange) {
                        rollFront();        // 滚动到上一页
                    } else {
                        rollBack();         // 滚回当前页
                    }
                }
                break;
        }
        return true;
    }

    private void exchangeBitmap(boolean tag) {
        // TODO 改变当前显示的图像
    }

    // 显示触摸结果
    private void showTouchResult(float x, float y, int clickType) {
       a = new PointF(x, y);
       mClickType = clickType;
       int fy = (mClickType == CLICK_TOP) ? 0 : viewHeight;
       f = new PointF(viewWidth, fy);
       calcEachPoint(a, f);
        PointF touchPoint = new PointF(x, y);
        if (calcPointCX(touchPoint, f) < 0) {   // 若 C 点的 x 坐标小于 0，就重测 C 点坐标
            calcPointA();           // 根据触摸点重新测量 A 点坐标
            calcEachPoint(a, f);
        }
        postInvalidate();
    }

    private float calcPointCX(PointF a, PointF f) {
        // TODO 计算 C 点的 X 坐标
        return 0;
    }

    private void calcPointA() {
        // TODO 重新测量 A 点坐标
    }

    private void rollFront() {
        // TODO 滚动到上一页
    }

    private void rollBack() {
        // TODO 滚回当前页
    }


    /**
     * 手指松开后，要判断接下来是往前翻页，还是往后缩回去，并在往前翻与后缩的过程中展示翻书动画
     */
    private Scroller mScroller;     // 滚动器对象

    private void initView(Context context) {
        // 创建一个基于线性插值器的滚动器对象
        mScroller = new Scroller(context, new LinearInterpolator());
    }

    // 在滚动器滑动过程中不断触发，计算并显示视图界面
    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            // 尚未滚动完毕
            int x = mScroller.getCurrX();
            int y = mScroller.getCurrY();
            showTouchResult(x, y, mClickType);  // 显示触摸结果
            // 已经滚到终点了
            if (mScroller.getFinalX() == x && mScroller.getFinalY() == y) {
                if (needChange) {
                    exchangeBitmap(true);   // 改变当前显示的图像
                }
                reset();    // 回到默认状态
            }
        }
    }

    private void reset() {
        // TODO 回到默认状态
    }
}
